package com.hcy.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hcy.business.service.UserServiceBz;
import com.hcy.rabbitbasicmodel.dto.MyPage;
import com.hcy.rabbitbasicmodel.enums.Clients;
import com.hcy.userdomin.domain.entity.*;
import com.hcy.userdomin.domain.mapper.MenuInfoMapper;
import com.hcy.userdomin.domain.mapper.RoleMapper;
import com.hcy.userdomin.domain.mapper.RoleMenuMapper;
import com.hcy.userdomin.domain.mapper.UserMapper;
import com.hcy.userdomin.domain.service.impl.*;
import com.hcy.usermodel.dto.MenuInfoTree;
import com.hcy.usermodel.dto.request.*;
import com.hcy.usermodel.dto.response.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * @Author huchenying
 * Description:
 * @Date 2021/11/20 13:46
 */
@Service
public class UserServiceBzImpl implements UserServiceBz {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceBzImpl.class);

    @Resource
    private UserMapper userMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private UserServiceImpl userService;
    @Resource
    private RoleServiceImpl roleService;
    @Resource
    private RoleMenuServiceImpl roleMenuService;
    @Resource
    private RoleMenuMapper roleMenuMapper;
    @Resource
    private MenuInfoServiceImpl menuInfoService;
    @Resource
    private OperateLogServiceImpl operateLogService;
    @Resource
    private UserRoleServiceImpl userRoleService;
    @Resource
    private CustomerInfoServiceImpl customerInfoService;
    @Resource
    private MoneyChangeLogServiceImpl moneyChangeLogService;
    @Resource
    private EvaluateServiceImpl evaluateService;
    @Resource
    private RoutesTableServiceImpl routesTableService;
    @Resource
    private MenuInfoMapper menuInfoMapper;

    @Override
    public void evaluation(EvaluationRequestDTO requestDTO) {
        Evaluate evaluate = new Evaluate();
        BeanUtils.copyProperties(requestDTO, evaluate);
        evaluateService.save(evaluate);
    }

    @Override
    public CustomerInfoResponseDTO getBaseInfo(String phone) {
        LambdaQueryWrapper<CustomerInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CustomerInfo::getPhone, phone);
        CustomerInfo one = customerInfoService.getOne(queryWrapper);
        CustomerInfoResponseDTO responseDTO = new CustomerInfoResponseDTO();
        BeanUtils.copyProperties(one, responseDTO);
        return responseDTO;
    }

    @Override
    public List<RoutesResponseDTO> getRoutesList() {
        LambdaQueryWrapper<RoutesTable> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderBy(true, false, RoutesTable::getCreateTime);
        Page<RoutesTable> page = routesTableService.page(new Page<>(1, 5), queryWrapper);
        List<RoutesResponseDTO> responseDTOList = new ArrayList<>();
        List<RoutesTable> records = page.getRecords();
        for (RoutesTable record : records) {
            RoutesResponseDTO routesResponseDTO = new RoutesResponseDTO();
            BeanUtils.copyProperties(record, routesResponseDTO);
            responseDTOList.add(routesResponseDTO);
        }
        return responseDTOList;
    }

    @Override
    public void addRoutes(UploadRoutesRequestDTO requestDTO) {
        RoutesTable routesTable = new RoutesTable();
        routesTable.setRoutes(requestDTO.getRoutes());
        routesTable.setCreateTime(new Date());
        routesTable.setManagerName(requestDTO.getManagerName());
        boolean save = routesTableService.save(routesTable);
        if (!save) {
            throw new RuntimeException("路由表添加失败！");
        }
    }

    @Override
    public MyPage<UserAuthsResponseDTO> getUserList(UserAuthRequestDTO requestDTO) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getBusinessCode, requestDTO.getBusinessCode());
        queryWrapper.eq(StringUtils.isNotEmpty(requestDTO.getUsername()),User::getUsername, requestDTO.getUsername());

        Page<UserAuthsResponseDTO> page = userMapper.getUserList(new Page<>(requestDTO.getPageNO(), requestDTO.getPageSize()), requestDTO.getBusinessCode(),requestDTO.getUsername());
        for (UserAuthsResponseDTO record : page.getRecords()) {
            String roleIds = record.getRoleIds();
            if (roleIds == null) {
                continue;
            }
            String[] split = roleIds.split(",");
            if (split.length < 1) {
                continue;
            }
            List<Integer> roles = new ArrayList<>();
            for (String s : split) {
                roles.add(Integer.parseInt(s));
            }
            record.setRoleIdList(roles);
        }
        MyPage<UserAuthsResponseDTO> responseDTOMyPage = new MyPage<>(page.getCurrent(), page.getSize(), page.getTotal());
        responseDTOMyPage.setRecords(page.getRecords());
        return responseDTOMyPage;
    }

    @Override
    public UserAuthsResponseDTO insertOrUpdateManager(UserAuthRequestDTO requestDTO) {
        User user = new User();
        BeanUtils.copyProperties(requestDTO, user);
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getBusinessCode, requestDTO.getBusinessCode());
        queryWrapper.eq(User::getUsername, requestDTO.getUsername());
        boolean b = userService.saveOrUpdate(user, queryWrapper);
        if (!b) {
            throw new RuntimeException("添加或更新失败");
        }
        // 如果添加的是乘客，初始化乘客信息
        if(Clients.CUSTOMER.getName().equals(requestDTO.getBusinessCode())){
            CustomerInfo customerInfo = new CustomerInfo();
            // 初始化信息
            customerInfo.setPhone(requestDTO.getUsername());
            customerInfo.setPassengerName(requestDTO.getNickname());
            boolean save = customerInfoService.save(customerInfo);
            if(!save){
                throw new RuntimeException("添加或更新失败");
            }
        }

        UserAuthsResponseDTO responseDTO = new UserAuthsResponseDTO();
        BeanUtils.copyProperties(user, responseDTO);
        return responseDTO;
    }

    public List<RoleResponseDTO> getRoleList0(UserAuthRequestDTO requestDTO) {
        List<RoleResponseDTO> responseDTOList = new ArrayList<>();
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Role::getBusinessCode, requestDTO.getBusinessCode());
        Page<Role> page = roleService.page(new Page<>(requestDTO.getPageNO(), requestDTO.getPageSize()), queryWrapper);
        for (Role record : page.getRecords()) {
            RoleResponseDTO responseDTO = new RoleResponseDTO();
            BeanUtils.copyProperties(record, responseDTO);
            responseDTOList.add(responseDTO);
        }
        return responseDTOList;
    }

    @Override
    public List<RoleResponseDTO> getRoleList(UserAuthRequestDTO requestDTO) {
        List<RoleResponseDTO> responseDTOList = new ArrayList<>();
        List<RoleResponseDTO> records = roleMapper.getRoleDetailList(requestDTO.getBusinessCode());
        for (RoleResponseDTO record : records) {
            if (record.getMenuListString() == null) {
                record.setMenuList(new ArrayList<>());
                responseDTOList.add(record);
                continue;
            }
            // 获取的是 menu url
            String[] split = record.getMenuListString().split(",");
            String[] split2 = record.getMenuIdString().split(",");
            if (split.length < 1) {
                record.setMenuList(new ArrayList<>());
                record.setMenuIds(new ArrayList<>());
                responseDTOList.add(record);
                continue;
            }
            List<String> menuList = new ArrayList<>(Arrays.asList(split));
            List<Integer> menuList2 = new ArrayList<>();
            for (String s : split2) {
                menuList2.add(Integer.parseInt(s));
            }
            record.setMenuList(menuList);
            record.setMenuIds(menuList2);
            responseDTOList.add(record);
        }
        return responseDTOList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RoleResponseDTO addRole(RoleResponseDTO requestDTO) {
        Role role = new Role();
        role.setName(requestDTO.getName());
        role.setBusinessCode(requestDTO.getBusinessCode());
        boolean save = roleService.save(role);
        if (!save) {
            throw new RuntimeException("添加角色失败");
        }
        //绑定菜单
        List<Integer> menuIds = requestDTO.getMenuIds();
        List<RoleMenu> roleMenus = new ArrayList<>();
        for (Integer n : menuIds) {
            RoleMenu roleMenu = new RoleMenu(role.getId(), n);
            roleMenus.add(roleMenu);
        }
        boolean b = roleMenuService.saveBatch(roleMenus);
        if (!b) {
            throw new RuntimeException("保存失败");
        }
        RoleResponseDTO responseDTO = new RoleResponseDTO();
        BeanUtils.copyProperties(role, responseDTO);
        return responseDTO;
    }

    @Override
    public void deleteUser(UserAuthRequestDTO requestDTO) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, requestDTO.getUsername());
        queryWrapper.eq(User::getBusinessCode, requestDTO.getBusinessCode());
        boolean remove = userService.remove(queryWrapper);
        if (!remove) {
            throw new RuntimeException("删除失败");
        }
    }

    @Override
    public void deleteRole(RoleResponseDTO requestDTO) {

        //删除角色绑定的所有菜单
        LambdaQueryWrapper<RoleMenu> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(RoleMenu::getRid, requestDTO.getId());
        boolean remove1 = roleMenuService.remove(queryWrapper1);
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Role::getId, requestDTO.getId());
        queryWrapper.eq(Role::getBusinessCode, requestDTO.getBusinessCode());
        boolean remove2 = roleService.remove(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserRole(RoleUpdateRequestDTO requestDTO) {
        //更新该用户信息
        LambdaQueryWrapper<User> queryWrapper2 = new LambdaQueryWrapper<>();
        queryWrapper2.eq(User::getBusinessCode, Clients.MANAGER.getName());
        queryWrapper2.eq(User::getUsername, requestDTO.getUsername());
        User one1 = userService.getOne(queryWrapper2);
        one1.setNickname(requestDTO.getNickname());
        if (requestDTO.getIsChangePassword()) {
            one1.setPassword(requestDTO.getPassword());
        }
        boolean b = userService.update(one1, queryWrapper2);
        if (!b) {
            throw new RuntimeException("更新用户信息失败");
        }

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, requestDTO.getUsername());
        queryWrapper.eq(User::getBusinessCode, Clients.MANAGER.getName());
        User one = userService.getOne(queryWrapper);
        Integer uid = one.getId();
        //删除该用户所有的角色
        LambdaQueryWrapper<UserRole> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(UserRole::getUserId, one.getId());
        boolean remove = userRoleService.remove(queryWrapper1);
        List<Integer> list = requestDTO.getRoleIdList();
        String managerName = Clients.MANAGER.getName();
        if (list.size() > 0) {
            ArrayList<UserRole> userRoles = new ArrayList<>();
            for (Integer roleId : list) {
                UserRole userRole = new UserRole(uid, roleId, managerName);
                userRoles.add(userRole);
            }
            //添加传过来的角色
            boolean b2 = userRoleService.saveBatch(userRoles);
            if (!b2) {
                throw new RuntimeException("角色更新失败");
            }
        }
    }

    @Override
    public void addOptLog(AddLogRequestDTO requestDTO) {
        OperateLog operateLog = new OperateLog();
        BeanUtils.copyProperties(requestDTO, operateLog);
        boolean save = operateLogService.save(operateLog);
        if (!save) {
            throw new RuntimeException("操作日志插入失败");
        }
    }

    @Override
    public MenuResponseDTO getMenuTree() {
        // 获取菜单树
        List<MenuInfoTree> menuInfoTree = menuInfoMapper.getMenuTree();
        MenuResponseDTO root = new MenuResponseDTO();
        Map<Integer, MenuResponseDTO> memory = new HashMap<>();
        memory.put(0, root);
        for (MenuInfoTree infoTree : menuInfoTree) {
            String[] ids = infoTree.getIds().split(",");
            String[] pids = infoTree.getPids().split(",");
            String[] urls = infoTree.getUrls().split(",");
            String[] names = infoTree.getNames().split(",");
            Integer level = Integer.parseInt(infoTree.getLevel());
            for (int i = 0; i < ids.length; i++) {
                // 放入root中
                MenuResponseDTO node = new MenuResponseDTO();
                int id = Integer.parseInt(ids[i]);
                node.setId(id);
                node.setLevel(level);
                node.setName(names[i]);
                node.setUrl(urls[i]);
                int pid = Integer.parseInt(pids[i]);
                node.setPid(pid);
                MenuResponseDTO parent = memory.get(pid);
                if (parent.getChildren() == null) {
                    parent.setChildren(new HashSet<>());
                }
                parent.getChildren().add(node);
                memory.put(id, node);
            }
        }
        return root;
    }

    @Override
    public MenuResponseDTO addMenu(MenuRequestDTO requestDTO) {
        MenuInfo menuInfo = new MenuInfo();
        BeanUtils.copyProperties(requestDTO, menuInfo);
        if (requestDTO.getPid() == null) {
            menuInfo.setPid(0);
        }
        if (menuInfo.getPid() != 0) {
            MenuInfo byId = menuInfoService.getById(menuInfo.getPid());
            if (byId == null) {
                throw new RuntimeException("找不到pid");
            }
            menuInfo.setLevel(byId.getLevel() + 1);
        } else {
            menuInfo.setLevel(1);
        }

        boolean save = menuInfoService.save(menuInfo);
        if (!save) {
            throw new RuntimeException("菜单添加失败");
        }
        MenuResponseDTO responseDTO = new MenuResponseDTO();
        BeanUtils.copyProperties(menuInfo, responseDTO);
        return responseDTO;
    }

    @Override
    public void deleteMenu(MenuRequestDTO requestDTO) {

        if (requestDTO.getId() == null && CollectionUtils.isEmpty(requestDTO.getDeleteIds())) {
            return;
        }

        List<Integer> param;
        if (requestDTO.getId() == null) {
            param = requestDTO.getDeleteIds();
        } else {
            param = new ArrayList<>();
            param.add(requestDTO.getId());
        }
        // 找到以这个菜单的孩子的ids
        LambdaQueryWrapper<MenuInfo> queryWrapper2 = new LambdaQueryWrapper<>();
        queryWrapper2.in(MenuInfo::getPid, param);
        List<MenuInfo> list = menuInfoService.list(queryWrapper2);
        MenuRequestDTO nextMenuRequestDTO = new MenuRequestDTO();
        List<Integer> deleteIds = new ArrayList<>();
        for (MenuInfo menuInfo : list) {
            deleteIds.add(menuInfo.getId());
        }
        nextMenuRequestDTO.setDeleteIds(deleteIds);
        deleteMenu(nextMenuRequestDTO);
        //删除
        LambdaQueryWrapper<MenuInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(MenuInfo::getId, param);
        boolean remove = menuInfoService.remove(queryWrapper);

    }

    /**
     * @Author huchenying
     * @Description 根据用户名和用户标识，获取角色和菜单
     * @Date 2022/4/23 1:19
     **/
    @Override
    public ManagerPermissionResponseDTO getUserRoleMenu(UserAuthRequestDTO requestDto) {
        ManagerPermissionResponseDTO responseDTO = new ManagerPermissionResponseDTO();
        UserAuthsResponseDTO authsByName = userMapper.getAuthsByName(requestDto);
        BeanUtils.copyProperties(authsByName, responseDTO);
        if (StringUtils.isEmpty(authsByName.getAuthorities())) {
            return responseDTO;
        }
        String[] split = authsByName.getAuthorities().split(",");
        if (split.length < 1) {
            return responseDTO;
        }
        List<String> roles = new ArrayList<>(Arrays.asList(split));

        List<UserAuthsResponseDTO> userRoleMenu = userMapper.getUserRoleMenu(authsByName.getRoleIds());
        Set<String> set = new HashSet<>();
        for (UserAuthsResponseDTO roleMenu : userRoleMenu) {
            if (roleMenu == null || StringUtils.isEmpty(roleMenu.getMString())) {
                continue;
            }
            String[] menusUrl = roleMenu.getMString().split(",");
            if (menusUrl.length < 1) {
                continue;
            }
            set.addAll(Arrays.asList(menusUrl));
        }

        List<String> menuList = new ArrayList<>(set);

        responseDTO.setMenus(menuList);
        responseDTO.setRoles(roles);

        return responseDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRoleMenu(MenuRequestDTO requestDTO) {
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Role::getId, requestDTO.getRoleId());
        queryWrapper.eq(Role::getBusinessCode, requestDTO.getBusinessCode());
        Role one = roleService.getOne(queryWrapper);
        //更新role
        if (!one.getName().equals(requestDTO.getRoleName())) {
            boolean update = roleService.update(one, queryWrapper);
            if (!update) {
                throw new RuntimeException("更新角色失败");
            }
        }
        Integer rid = one.getId();
        LambdaQueryWrapper<RoleMenu> roleMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roleMenuLambdaQueryWrapper.eq(RoleMenu::getRid, rid);
        boolean remove = roleMenuService.remove(roleMenuLambdaQueryWrapper);
        List<Integer> menuIds = requestDTO.getMenuIds();
        if (menuIds.size() > 0) {
            List<RoleMenu> roleMenus = new ArrayList<>();
            for (Integer n : menuIds) {
                RoleMenu roleMenu = new RoleMenu(rid, n);
                roleMenus.add(roleMenu);
            }
            boolean b = roleMenuService.saveBatch(roleMenus);
            if (!b) {
                throw new RuntimeException("保存失败");
            }
        }
    }

    @Override
    public MyPage<UserAuthsResponseDTO> getCustomerList(UserAuthRequestDTO requestDTO) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getBusinessCode, requestDTO.getBusinessCode());

        Page<User> page = userService.page(new Page<>(requestDTO.getPageNO(), requestDTO.getPageSize()), queryWrapper);
        List<User> records = page.getRecords();
        List<UserAuthsResponseDTO> res = new ArrayList<>();
        for (User record : records) {
            UserAuthsResponseDTO responseDTO = new UserAuthsResponseDTO();
            BeanUtils.copyProperties(record, responseDTO);
            res.add(responseDTO);
        }

        MyPage<UserAuthsResponseDTO> responseDTOMyPage = new MyPage<>(page.getCurrent(), page.getSize(), page.getTotal());
        responseDTOMyPage.setRecords(res);

        return responseDTOMyPage;
    }

    @Override
    public void addTestUser(UserAuthRequestDTO user) {
        User user1 = new User();
        user1.setUsername(user.getUsername());
        user1.setPassword(user.getPassword());
        user1.setNickname("测试");
        user1.setBusinessCode("driver");

        userService.save(user1);
    }

//    /**
//     * @Author huchenying
//     * @Description TODO 有机会通过分布式事务框架进行重构
//     * @Date 2022/4/7 14:33
//     **/
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void consumerPay(String payNumber) {
//        logger.info("consumerPay start param -> {}", ToStringBuilder.reflectionToString(payNumber));
//        PayOrderRequestDTO payOrderRequestDTO = new PayOrderRequestDTO();
//        payOrderRequestDTO.setPayNumber(payNumber);
//        ResponseData<PayOrderResponseDTO> payOrder = orderBaseClient.getPayOrder(payOrderRequestDTO);
//        if (payOrder.getCode() != Code.Success) {
//            throw new RuntimeException("调用订单服务查询支付单失败:" + payNumber);
//        }
//        PayOrderResponseDTO data = payOrder.getData();
//        Double tailPrice = data.getTailPrice();
//        changeCoin(data.getCustomerId(),tailPrice);
//    }

    @Override
    public CustomerInfoResponseDTO changeCoin(String phone, Double change) {
        LambdaQueryWrapper<CustomerInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CustomerInfo::getPhone, phone);
        CustomerInfo one = customerInfoService.getOne(queryWrapper);
        BigDecimal balance = one.getBalance();
        BigDecimal add;
        add = balance.add(new BigDecimal(change));
        int i = add.compareTo(new BigDecimal(0));
        if (i < 0) {
            throw new RuntimeException("余额不足以支付");
        }
        one.setBalance(add);
        LambdaQueryWrapper<CustomerInfo> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(CustomerInfo::getBalance, balance);
        queryWrapper1.eq(CustomerInfo::getPhone, one.getPhone());
        boolean update = customerInfoService.update(one, queryWrapper1);
        if (!update) {
            throw new RuntimeException("余额更新失败！");
        }
        one.setBalance(add);
        CustomerInfoResponseDTO responseDTO = new CustomerInfoResponseDTO();
        BeanUtils.copyProperties(one, responseDTO);
        return responseDTO;
    }

    /**
     * @Author huchenying
     * @Description 获取用户的权限信息
     * @Date 2021/11/20 13:55
     **/
    @Override
    public UserAuthsResponseDTO getAuthsByName(UserAuthRequestDTO requestDto) {
        logger.info("getAuthsByName start param ->{}", requestDto);

        UserAuthsResponseDTO authsResponseDto = userMapper.getAuthsByName(requestDto);

        logger.info("getAuthsByName end result -> {}", authsResponseDto);
        return authsResponseDto;
    }
}
